/**
 * Copyright (c) 2012 Nokia Corporation.
 * All rights reserved.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#include "placeslistmodel.h"

#include <QDebug>
#include <QDir>
#include <QLandmarkCategoryFilter>

// Constants
const int UpdateInterval(1000);
const QString CategoryName("Places Around");


/*!
  \class PlacesListModel
  \brief This class represents a model containing Facebook places data.
*/


/*!
  Constructor.
*/
PlacesListModel::PlacesListModel(QObject *parent)
    : QAbstractListModel(parent),
      m_landmarkManager(0),
      m_initialized(false)
{
    QHash<int, QByteArray> roles;
    roles[IdRole] = "placeid";
    roles[NameRole] = "placename";
    roles[AddressRole] = "placeaddress";
    roles[LatitudeRole] = "placelatitude";
    roles[LongitudeRole] = "placelongitude";
    setRoleNames(roles);

    m_landmarkManager = new QLandmarkManager(this);

    connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(saveNewLandmarks()));
    m_updateTimer.setSingleShot(true);

    initialize();
}


/*!
  Copy constructor.
  Not used.
*/
PlacesListModel::PlacesListModel(const PlacesListModel &model, QObject *parent)
    : QAbstractListModel(parent),
      m_landmarkManager(model.m_landmarkManager)
{
}


/*!
  Destructor.
*/
PlacesListModel::~PlacesListModel()
{
}


/*!
  From QAbstractListModel.
  Returns data from model by \a index by \a role.
*/
QVariant PlacesListModel::data(const QModelIndex &index,
                               int role /* Qt::DisplayRole */) const
{
    const int itemIndex(index.row());

    if (!index.isValid() || itemIndex >= m_visibleLandmarks.count()) {
        return QVariant();
    }

    QLandmark landmark = m_visibleLandmarks[itemIndex];

    QVariant value;

    switch (role) {
    case IdRole:
        value = QVariant::fromValue(landmark.description());
        break;
    case NameRole:
        value = QVariant::fromValue(landmark.name());
        break;
    case AddressRole:
        value = QVariant::fromValue(landmark.address().street());
        break;
    case LatitudeRole:
        value = QVariant::fromValue(landmark.coordinate().latitude());
        break;
    case LongitudeRole:
        value = QVariant::fromValue(landmark.coordinate().longitude());
        break;
    default:
        break;
    }

    return value;
}


/*!
  From QAbstractListModel.
  Returns the row count of the model.
*/
int PlacesListModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_visibleLandmarks.count();
}


/*!
  Returns the name of the landmark category used for the items in this model.
*/
QString PlacesListModel::categoryName() const
{
    return m_category.name();
}


/*!
  Updates the new places in \a data to the model.
*/
void PlacesListModel::updatePlacesData(const QVariant &data)
{
    clearVisibleLandmarks();
    m_allLandmarks.clear();
    QVariantList places(data.toList());

    foreach (QVariant temp, places) {
        // Get needed data from the dictionary tree.
        QVariantMap place(temp.toMap());
        QString id(place["id"].toString());
        QString name(place["name"].toString());
        double latitude(place["location"].value<QVariantMap>()["latitude"].toDouble());
        double longitude(place["location"].value<QVariantMap>()["longitude"].toDouble());
        QString street(place["location"].value<QVariantMap>()["street"].toString());

        // Construct a landmark from data.
        QLandmark newLandmark;
        QGeoCoordinate geoCoordinate(latitude, longitude);
        QGeoAddress geoAddress;
        geoAddress.setStreet(street);
        newLandmark.setDescription(id); // Description field is used for storing the page ID.
        newLandmark.setName(name);
        newLandmark.setCoordinate(geoCoordinate);
        newLandmark.setAddress(geoAddress);
        newLandmark.addCategoryId(m_category.categoryId());
        m_allLandmarks.append(newLandmark);
    }

    updateVisibleLandmarks();
}


/*!
  Updates visible model items based on the text in the filter text.
*/
void PlacesListModel::updateVisibleLandmarks()
{
    qDebug() << "PlacesListModel::updateVisibleLandmarks()";
    clearVisibleLandmarks();
    removeOldLandmarks();

    foreach (QLandmark landmark, m_allLandmarks) {
        if (landmark.name().contains(m_filter, Qt::CaseInsensitive)
                || m_filter.isEmpty())
        {
            addVisibleLandmark(landmark);
        }
    }

    // Update landmark items after an interval.
    m_updateTimer.start(UpdateInterval);
}


/*!
  Sets filter text to the model.
*/
void PlacesListModel::setFilter(const QString &filterText)
{
    if (m_filter != filterText) {
        m_filter = filterText;
        updateVisibleLandmarks();
    }
}


/*!
  Clears all visible landmarks from the model.
*/
void PlacesListModel::clearVisibleLandmarks()
{
    qDebug() << "PlacesListModel::clearVisibleLandmarks()";
    const int count(m_visibleLandmarks.count());
    beginRemoveRows(QModelIndex(), 0, count - 1);
    m_visibleLandmarks.clear();
    endRemoveRows();
}


/*!
  Adds a visible landmark to the model.
*/
void PlacesListModel::addVisibleLandmark(const QLandmark &landmark)
{
    qDebug() << "PlacesListModel::addVisibleLandmark():" << landmark.name();

    const int count(m_visibleLandmarks.count());
    beginInsertRows(QModelIndex(), count, count);
    m_visibleLandmarks.append(landmark);
    endInsertRows();
}


/*!
  Saves the visible landmarks to the database.
*/
void PlacesListModel::saveNewLandmarks()
{
    if (!m_landmarkManager->saveLandmarks(&m_visibleLandmarks)) {
        qDebug() << "PlacesListModel::saveNewLandmarks():"
                 << "QLandmarkManager::saveLandmarks() failed!";
        emit error(m_landmarkManager->errorString());
        return;
    }

    qDebug() << "PlacesListModel::saveNewLandmarks(): "
             << m_visibleLandmarks.count() << "landmarks saved.";
    emit visibleItemsUpdated();
}


/*!
  Creates a new landmark category for this application if one does not exist.
*/
void PlacesListModel::initialize()
{
    qDebug() << "PlacesListModel::initialize(): QLandmarkManager URI:"
             << m_landmarkManager->managerUri();

    // Get Places Around category ID from manager if found.
    bool found(false);
    QList<QLandmarkCategory> categories = m_landmarkManager->categories();

    if (categories.count() > 0) {
        foreach (QLandmarkCategory category, categories) {
            if (category.name().compare(CategoryName) == 0) {
                m_category = category;
                emit categoryNameChanged(m_category.name());
                found = true;
                break;
            }
        }
    }

    if (!found) {
        // Create new category for Places Around places.
        m_category.setName(CategoryName);
        m_landmarkManager->saveCategory(&m_category);
        emit categoryNameChanged(m_category.name());
    }
    else {
        // Clear the old landmarks.
        removeOldLandmarks();
    }

    qDebug() << "PlacesListModel::initialize(): Category:"
             << m_category.categoryId().localId();
}


/*!
  Removes the old landmarks from the database.
*/
void PlacesListModel::removeOldLandmarks()
{
    QLandmarkCategoryFilter filter;
    filter.setCategoryId(m_category.categoryId());
    QList<QLandmark> oldLandmarks = m_landmarkManager->landmarks(filter);
    m_landmarkManager->removeLandmarks(oldLandmarks);

    qDebug() << "PlacesListModel::removeOldLandmarks():"
             << oldLandmarks.count() << "old landmarks removed.";
}
